using System;
using System.Linq;
using System.Web.Security;

using Azure.Domain.Models;
using Azure.Membership;
using Azure.Web.Stubs;
using Rhino.Mocks;

using Xunit;

namespace Azure.Tests.Membership
{
    public class ProviderFacts : Facts<AzureMembershipProvider>
    {
        public ProviderFacts()
        {
            AzureMembershipProvider.LoadRepository = () => new MembershipRepository(new StubRepository<User>()); 
        }

        public IMembershipRepository Repository
        {
            get { return Mock<IMembershipRepository>(); }
        }

        [Fact]
        public void HashPasswordWorksAsExpected()
        {
            const string expected = "uPlhSA7DpYSaAKL6AjGwy2MQfHs=";
            var result = ClassUnderTest.HashPassword("test", "foo");
            Assert.Equal(expected, result);
        }

        [Fact]
        public void ValidateReturnsTrueForValidUser()
        {
            Repository.Expect(x => x.LoadByUsername("test")).Return(new User
                                                                         {
                                                                             PartitionKey = Guid.NewGuid().ToString(),
                                                                             UserName = "test",
                                                                             Password = "qUqP5cyxm6YcTAhz05Hph5gvu9M="
                                                                         });
            var result = ClassUnderTest.ValidateUser("test", "test");

            Assert.True(result);
        }

        [Fact]
        public void ValidateReturnsFalseForUnknownUser()
        {
            var result = ClassUnderTest.ValidateUser("test", "test");

            Assert.False(result);
        }

        [Fact]
        public void ValidateReturnsFalseForBadPassword()
        {
            Repository.Expect(x => x.LoadByUsername("test")).Return(new User
            {
                PartitionKey = Guid.NewGuid().ToString(),
                UserName = "test",
                Password = "qUqP5cyxm6YcTAhz05Hph5gvu9M="
            });

            var result = ClassUnderTest.ValidateUser("test", "test1");

            Assert.False(result);
        }

        [Fact]
        public void CreateUserWorks()
        {
            MembershipCreateStatus membershipCreateStatus;
            string username = "test-user";
            string password = "Pass@word1";
            string email = "test@you.com";
            string passwordQuestion = "Is this required?";
            string passwordAnswer = "Yes it is";
            bool approved = true;
            object providerUserKey = Guid.NewGuid();

            var user = ClassUnderTest.CreateUser(
                username,
                password,
                email,
                passwordQuestion,
                passwordAnswer,
                approved,
                providerUserKey,
                out membershipCreateStatus);

            Assert.Equal(MembershipCreateStatus.Success, membershipCreateStatus);
            Assert.NotNull(user);
            Assert.Equal(username, user.UserName);
        }

        [Fact]
        public void GetUserNameByEmailWorksAsExpected()
        {
            Repository.Stub(x => x.LoadByEmail("test@you.com")).Return(new User { Email = "test@you.com", UserName = "test-user" });

            var username = ClassUnderTest.GetUserNameByEmail("test@you.com");

            Assert.Equal("test-user", username);
        }

        [Fact]
        public void GetUserNameByEmailReturnsEmptyStringWhenUserNotFound()
        {
            var username = ClassUnderTest.GetUserNameByEmail("test@you.com");

            Assert.Equal(string.Empty, username);
        }

        [Fact]
        public void GetUserReturnsAMembershipUserObjectIfUserIsFound()
        {
            Repository.Expect(x => x.LoadByUsername("test-user")).Return(new User { Email = "test@you.com", UserName = "test-user" });
            var result = ClassUnderTest.GetUser("test-user", true);
            Assert.NotNull(result);
            Assert.Equal("test-user", result.UserName);
        }

        [Fact]
        public void GetUserReturnsNullIfUserIsNotFound()
        {
            var result = ClassUnderTest.GetUser("test-user", true);
            Assert.Null(result);
        }
    }
}